package com.myaihui.service.impl;

import com.myaihui.domain.Resource;
import com.myaihui.domain.Role;
import com.myaihui.domain.SysUser;
import com.myaihui.foundation.constant.SysConst;
import com.myaihui.foundation.model.PagerQuery;
import com.myaihui.foundation.query.UserQuery;
import com.myaihui.repository.ResourceRepository;
import com.myaihui.repository.RoleRepository;
import com.myaihui.repository.SysUserRepository;
import com.myaihui.service.CustomSysUserRepository;
import com.myaihui.service.SysUserService;
import com.myaihui.util.EncryptUtil;
import com.myaihui.util.LoginUtil;
import org.apache.shiro.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by sun on 2018/6/6.
 *
 * @author sunfuchang03@126.com
 * @version 1.0
 * @since 1.0
 */
@Service
public class SysUserServiceImpl extends BasePageableServiceImpl<SysUser, String> implements SysUserService {
    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Static fields/constants/initializer
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    private static Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Instance fields
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    private SysUserRepository sysUserRepository;
    @Autowired
    private CustomSysUserRepository customSysUserRepository;
    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private ResourceRepository resourceRepository;

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Constructors
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    @Autowired
    public SysUserServiceImpl(SysUserRepository sysUserRepository) {
        super(sysUserRepository);
        this.sysUserRepository = sysUserRepository;
    }

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Public Methods
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    @Override
    public SysUser findByUsername(String username) {
        if (!StringUtils.hasLength(username)) {
            return null;
        }
        return sysUserRepository.findByUsername(username);
    }

    @Override
    public SysUser add(String username, String password, Integer type, String platformId, String createdId) {
        SysUser sysUser = new SysUser();
        sysUser.setUsername(username);
        sysUser.setPassword(EncryptUtil.passwordEncrypt(username, password));
        sysUser.setType(type);
        sysUser.setPlatformId(platformId);
        sysUser.setPlatformType(type);
        return sysUserRepository.save(sysUser);
    }

    @Override
    public SysUser modifyPassword(Integer type, String platformId, String password) {
        SysUser sysUser = sysUserRepository.findByTypeAndPlatformId(type, platformId);
        sysUser.setPassword(EncryptUtil.passwordEncrypt(sysUser.getUsername(), password));
        return sysUser;
    }

    @Override
    public SysUser findByTypeAndPlatformId(Integer type, String platformId) {
        return sysUserRepository.findByTypeAndPlatformId(type, platformId);
    }

    @Override
    public SysUser findByUserNameWithRolesAndResources(String username) {
        if (!StringUtils.hasLength(username)) {
            return null;
        }
        return customSysUserRepository.findWithRolesAndResourcesByUsername(username);
    }

    @Override
    public List<Role> findRolesByUserId(String userId) {
        Assert.hasLength(userId, "UserId must not be null.");
        return roleRepository.findByUserId(userId);
    }

    @Override
    public List<Resource> findResourcesByUserId(String userId) {
        Assert.hasLength(userId, "UserId must not be null.");
        return resourceRepository.findByUserId(userId);
    }

    @Override
    public Specification<SysUser> buildSpecification(PagerQuery query) {
        Assert.notNull(query, "Query must not be null.");
        UserQuery userQuery = (UserQuery) query;
        return (root, cq, cb) -> {
            String username = userQuery.getUsername();
            String realname = userQuery.getRealname();
            Integer state = userQuery.getState();
            String platformId = userQuery.getPlatformId();
            Integer platformType = userQuery.getPlatformType();
            Integer type = userQuery.getType();
            boolean onlyAdmin = userQuery.isAdmin();

            List<Predicate> predicates = new LinkedList<>();
            if (StringUtils.hasLength(username)) {
                predicates.add(cb.like(root.get("username"), "%" + username + "%"));
            }
            if (StringUtils.hasLength(realname)) {
                predicates.add(cb.like(root.get("realName"), "%" + realname + "%"));
            }
            if (state != null) {
                predicates.add(cb.equal(root.get("state"), state));
            }
            if (StringUtils.hasLength(platformId)) {
                predicates.add(cb.equal(root.get("platformId"), platformId));
            }
            if (platformType != null) {
                predicates.add(cb.equal(root.get("platformType"), platformType));
            }
            if (type != null) {
                predicates.add(cb.equal(root.get("type"), type));
            }
            if (onlyAdmin && type == null) {
                predicates.add(cb.or(cb.equal(root.get("type"), SysConst.SubjectType.PLATFORM),
                        cb.equal(root.get("type"), SysConst.SubjectType.PROPERTY),
                        cb.equal(root.get("type"), SysConst.SubjectType.MALL)));
            }
            SysUser loginUser = LoginUtil.loginUser();
            predicates.add(cb.notEqual(root.get("id"), loginUser.getId()));
            predicates.add(cb.or(cb.equal(root.get("root"), false), cb.isNull(root.get("root"))));
            predicates.add(cb.equal(root.get("deleted"), false));
            if (predicates.size() > 0) {
                cq.orderBy(cb.desc(root.get("created")));
                cq.where(predicates.toArray(new Predicate[predicates.size()]));
            }
            return cq.getRestriction();
        };
    }

    @Override
    public boolean validatePassword(String userId, String pwd) {
        if (!StringUtils.hasLength(userId) || !StringUtils.hasLength(pwd))
            return false;
        SysUser user = sysUserRepository.findOne(userId);
        String destPwd = EncryptUtil.passwordEncrypt(user.getUsername(), pwd);
        String srcPwd = user.getPassword();
        return srcPwd.equals(destPwd);
    }

    @Override
    public void updatePassword(String userId, String pwd) {
        log.info("update user \"" + userId + "\"'s password to : " + pwd);
        if (!StringUtils.hasLength(userId) || !StringUtils.hasLength(pwd)) return;
        SysUser user = sysUserRepository.findOne(userId);
        String newPwd = EncryptUtil.passwordEncrypt(user.getUsername(), pwd);
        user.setPassword(newPwd);
        sysUserRepository.save(user);
    }

    @Override
    public SysUser findByUsernameExcludeId(String name, String userId) {
        org.springframework.util.Assert.hasLength(name, "name must not be null");
        org.springframework.util.Assert.hasLength(userId, "roleId must not be null");
        return sysUserRepository.findByUsernameAndIdIsNot(name, userId);
    }

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Private Methods
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */


}